package net.chowda.castcluster;

import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.DefaultHandler;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

import java.net.BindException;
import java.net.URL;
import java.net.JarURLConnection;
import java.io.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.List;
import java.util.ArrayList;

import net.chowda.castcluster.util.CastClusterConfig;
import com.sun.org.apache.xml.internal.utils.DOMBuilder;

import javax.xml.parsers.*;

/**
 * kicks off jetty.
 *
 * this application is ultimately a war file... after jetty is started, things should work
 * just like any other webapp.
 *
 */
public class Main {
    private static String configDir = System.getProperty("user.home") + File.separator + ".castcluster";
    private static String host = "localhost";
    private static String contextPath = "castcluster";
    private static List<String> virtualHosts = new ArrayList<String>(2);
    private static int port = 8080;

    public static void main(String[] args) throws Exception {
        deployWar("castcluster.war");
    }

    public static void deployWar(String warFile) throws Exception {
        getHost();

        Server server = new Server();
        Connector connector = new SelectChannelConnector();
        connector.setHost(host);
        connector.setPort(port);

        server.setConnectors(new Connector[]{connector});

        WebAppContext wac1 = new WebAppContext();
        wac1.setContextPath("/" + contextPath);
        wac1.setExtractWAR(true);
        wac1.setWar(warFile);

        if (virtualHosts.size() > 0) {
            wac1.setVirtualHosts(virtualHosts.toArray(new String[]{}));
        }

        ContextHandlerCollection contexts = new ContextHandlerCollection();
        contexts.setHandlers(new Handler[]{wac1});

        HandlerCollection handlers = new HandlerCollection();
        handlers.setHandlers(new Handler[]{contexts, new DefaultHandler()});
        server.setHandler(handlers);
        try {
            server.start();
            System.out.println("\n\n* CastCluster has started! access it at this URL: \n*\thttp://"+host+":"+port+"/"+contextPath+"\n\n");
        } catch (BindException e) {
            System.err.println("Could not bind to address!");
            e.printStackTrace();
        }
        server.join();
    }

    // here we see if there is a custom URL configured...
    // we can't use CastClusterConfig because it's part of the webapp and this Main is not...
    // TODO, once we're not suffering with the google project related JNLP issues, we can restructure our libs and do this the right way (CastClusterConfig)
    public static void getHost() {
        File configFile = new File(configDir + File.separator + "castcluster.xml");
        if(configFile.exists()) {
            try {
		        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder db = dbf.newDocumentBuilder();
                Document dom = db.parse(configFile);
                NodeList list = dom.getElementsByTagName("baseUrl");
                if(list != null && list.getLength() > 0) {
                    Node node = list.item(0);
                    String url = node.getTextContent();
                    if(!url.startsWith("http://")) {
                        throw new RuntimeException("your url (" + url + ") is invalid (does not start with http://) please change it in this file: " + configFile);
                    }
                    String regex = "http://(.*?):(\\d*)/(.*?)$";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(url);
                    if(matcher.find()) {
                        try {
                            host = matcher.group(1);
                            System.out.println("Found host: " + host);
                            port = Integer.parseInt(matcher.group(2));
                            System.out.println("Found port: " + port);
                            contextPath = matcher.group(3);
                            System.out.println("Found context: " + contextPath);
                        } catch (Exception e) {
                            throw new RuntimeException("I can't parse this URL: [" + url + "] it should be like http://localhost:8080/castcluster");
                        }
                    } else {
                        throw new RuntimeException("I can't parse this URL: [" + url + "] it should be like http://localhost:8080/castcluster");
                    }
                }

                // find virtual hosts
                list = dom.getElementsByTagName("virtualHost");
                for(int i = 0; i < list.getLength(); i++) {
                    String virtualHost = list.item(i).getTextContent();
                    System.out.println("Found virtual host: " + virtualHost);
                    virtualHosts.add(virtualHost);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            }
        }
    }
}
